(deftemplate automata
  (slot mean
    (type SYMBOL)
    (allowed-values init new))
  (slot state
    (type SYMBOL)
    (allowed-values alive dead))
  (slot xcoor
    (type INTEGER)
    (range 0 99))
  (slot ycoor
    (type INTEGER)
    (range 0 99))
  (slot is-neighbor-counted
    (type SYMBOL)
    (allowed-values TRUE FALSE)
    (default FALSE))
  (slot num-neighbors
    (type INTEGER)
    (default 0)
    (range 0 8)))

(deffunction how-many-alive-neighbor
  (?x ?y)
  (length (find-all-facts ((?a automata)) 
    (and (eq ?a:state alive) (eq ?a:mean init) (not (and (= ?a:xcoor ?x) (= ?a:ycoor ?y))) (>= 1 (abs (- ?a:xcoor ?x))) (>= 1 (abs (- ?a:ycoor ?y))))
)))

(defrule neighbor-counter
  ?counted <- (automata (mean init) (is-neighbor-counted FALSE) (xcoor ?x) (ycoor ?y))		;get the initally alive cells
=>
  (modify ?counted (is-neighbor-counted TRUE) (num-neighbors (+ (fact-slot-value ?counted num-neighbors) (funcall how-many-alive-neighbor ?x ?y))) ) )

(defrule populate
  (automata (mean init) (state dead) (num-neighbors 3) (xcoor ?x) (ycoor ?y))
=>
  (assert (automata (mean new) (state alive) (xcoor ?x) (ycoor ?y))))

(defrule loneliness
  (automata (mean init) (state alive) (num-neighbors ?v&:(< ?v 2)) (xcoor ?x) (ycoor ?y))
=>
  (assert (automata (mean new) (state dead) (xcoor ?x) (ycoor ?y))))

(defrule overcrowd
  (automata (mean init) (state alive) (num-neighbors ?v&:(> ?v 3)) (xcoor ?x) (ycoor ?y))
=>
  (assert (automata (mean new) (state dead) (xcoor ?x) (ycoor ?y))))

(defrule lives-on
  (automata (mean init) (state alive) (num-neighbors 2|3) (xcoor ?x) (ycoor ?y))
=>
  (assert (automata (mean new) (state alive) (xcoor ?x) (ycoor ?y))))

(defrule dark-mass
  (automata (mean init) (state dead) (num-neighbors ~3) (xcoor ?x) (ycoor ?y))
=>
  (assert (automata (mean new) (state dead) (xcoor ?x) (ycoor ?y))))